package cn.wp.common.core.plugin.scheduler;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.CronUtil;
import cn.wp.common.core.WpProperties;
import cn.wp.common.core.WpVar;
import cn.wp.common.core.model.WpError;
import cn.wp.common.core.plugin.email.MailService;
import cn.wp.common.core.util.ApplicationContextUtil;
import cn.wp.common.core.util.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.support.CronSequenceGenerator;

import java.io.InputStream;
import java.util.Map;

/**
 * 运行类
 * Created by chenyb on 2019/10/23
 */
public abstract class SchedulerRunnable implements Runnable {

    protected SchedulerTask schedulerTask;
    protected  Logger logger = LoggerFactory.getLogger(this.getClass());

    public SchedulerRunnable(SchedulerTask schedulerTask) {
        this.schedulerTask = schedulerTask;
    }

    @Override
    public void run() {
        SchedulerService schedulerService = ApplicationContextUtil.getBean(SchedulerService.class);
        MailService mailService = ApplicationContextUtil.getBean(MailService.class);

        try{

            if(!schedulerTask.isTest()){
                if(schedulerService.isRunning(schedulerTask.getTaskId())){
                    logger.info("定时器[" + schedulerTask + "]正在运行中,不能重复运行");
                    return;
                }
            }

            logger.info("定时器[" + schedulerTask + "]开始运行");

            schedulerTask.setLastStartRunDatetime(DateUtil.now());
            schedulerTask.setLastEndRunDatetime("");
            schedulerTask.setLastCost(-1);
            schedulerTask.setStatus(1);
            schedulerService.refreshTask(schedulerTask);
            long start = System.currentTimeMillis();

            // 执行任务
            this.runStart();

            long end = System.currentTimeMillis();
            long cost = (end - start) / 1000;

            schedulerTask.setStatus(2);
            schedulerTask.setLastCost(cost);
            schedulerTask.setLastEndRunDatetime(DateUtil.now());
            schedulerTask.setLastRunSuccess(0);

            if(!schedulerTask.isTest()) {
                schedulerService.refreshTask(schedulerTask);
            }

            logger.info("定时器[" + schedulerTask + "]运行完成，耗时：" + cost + " s");
        } catch (Throwable throwable){
            logger.error("定时器[ " + schedulerTask + " ]运行异常",throwable);
            logger.info("定时器[ " + schedulerTask + " ]运行异常, 任务将停止运行");

            // 非测试任务进行错误邮件发送等设置
            if(!schedulerTask.isTest()) {
                schedulerTask.setLastEndRunDatetime("");
                schedulerTask.setLastCost(-1);
                schedulerTask.setLastRunSuccess(1);
                // 需要重新初始化标记
                schedulerTask.setInit(true);
                schedulerService.stopTask(schedulerTask.getTaskId());
                WpError error = new WpError();
                error.setCreateDatetime(DateUtil.now());
                error.setMessage(throwable.getMessage());
                error.setObject(JSON.toJSONString(schedulerTask));
                error.setSysName("PPA");
                error.setTrace(ExceptionUtil.stacktraceToString(throwable));
                error.setType("定时器运行错误");

                // 错误邮件模板
                InputStream is = this.getClass().getResourceAsStream("/templates/email-tpl/emial-error.tpl");
                String htmlString = IoUtil.read(is, WpVar.ENCODE);
                IoUtil.close(is);
                // 发送错误邮件
                new Thread() {
                    @Override
                    public void run() {
                        String errorBody = mailService.mailHtmlBuilder(htmlString, BeanUtil.beanToMap(error));
                        String[] emails = ApplicationContextUtil.getBean(WpProperties.class).getEmailDevops();
                        mailService.sendMime(emails, "定时器运行出错", errorBody);
                    }
                }.start();
            }
        }
    }

    /**
     * 开始运行任务
     */
    public abstract void runStart();

    /**
     * 运行完成
     * @param schedulerTask
     */
    public abstract void runFinish(SchedulerTask schedulerTask);

}

